function AppViewModel() {
    
    // ==============================================
    //              Constants
    // ==============================================
    
    VIEW_MODE_PROPERTY_HEADER = "header";
    VIEW_MODE_PROPERTY_TEXT = "text";
    
    /**
     * This is a constant that will say what the property name is for when a data object has a collection of
     * modes that are associated with the current one. 
     */
    VIEW_MODE_PROPERTY_SUB_MODE = "subModes";
    
    /**
     * This property indicates which template to render.
     */
    VIEW_MODE_PROPERTY_TEMPLATE= "template";
    
    // ==============================================
    //              Data for "Projects"
    // ==============================================
    var projectPath         = "projects/";
    var proj1               = {title: "&quot;Foraging Frenzy&quot;", base: projectPath + "foraging-frenzy/index.html", thumb: projectPath + "foraging-frenzy/foraging-frenzy-thumb.png", description: " <p>&quot;Foraging Frenzy&quot; is a multi-player, top-down, 2D &quot;Paper, Rock, Scissors&quot; game variant and content management system.</p> <p> It&apos;s a good platform for exploring the Rational Unified Process (using UML to derive the design) high performance javascript, single page applications, SASS, google's closure compiler, and web sockets.</p> <p>Currently it is still in a prototype phase.</p><a href='projects/foraging-frenzy/index.html' target='_blank' class='blueBtnStyle'>Click here to play!</a>"};
    
    
    
    // ==============================================
    //              Data for "Drawings"
    // ==============================================
    
    var drawingPath         = "projects/drawings/";
    var drawing_1           = {img: drawingPath +  "DrawingBig1.jpg", thumb: drawingPath +   "DrawingSmall1.jpg", caption: 'Woman sitting in front of a bar.'};
    var drawing_2           = {img: drawingPath +  "DrawingBig2.jpg", thumb: drawingPath +   "DrawingSmall2.jpg", caption: 'Comparative Study: African vs. Greek Sculpture.'};
    var drawing_4           = {img: drawingPath +  "DrawingBig4.jpg", thumb: drawingPath +   "DrawingSmall4.jpg", caption: 'Sculpture: &quot;Dying Gladiator&quot;'};
    var drawing_5           = {img: drawingPath +  "DrawingBig5.jpg", thumb: drawingPath +   "DrawingSmall5.jpg", caption: 'Tigers at the Zoo.'};
    var drawing_6           = {img: drawingPath +  "DrawingBig6.jpg", thumb: drawingPath +   "DrawingSmall6.jpg", caption: 'Tomato, left-over dishes, sculptures at the Museum.'};
    var drawing_7           = {img: drawingPath +  "DrawingBig7.jpg", thumb: drawingPath +   "DrawingSmall7.jpg", caption: 'Sculpture: &quot;Bacchante with Faun&quot;'};
    var drawing_8           = {img: drawingPath +  "DrawingBig8.jpg", thumb: drawingPath +   "DrawingSmall8.jpg", caption: 'Variations on Chinese Folk Art Designs.'};
    var drawing_9           = {img: drawingPath +  "DrawingBig10.jpg", thumb: drawingPath +   "DrawingSmall10.jpg", caption: 'Two Sculptures.'};
    
    // ==============================================
    //              Data Views
    // ==============================================
    var error_occurred      = {header: 'Error', text: 'An Error Occurred', template: 'tmpl-error'};
    
    var info_schedule       = {header: 'Schedule', text: 'My daily schedule', template: 'tmpl-info-schedule'};
    var info_aboutMe        = {header: 'About Me', text: 'An introduction', template: 'tmpl-info-about-me'}
    
    var examples_drawings   = {header: 'Drawings', text: '', template: 'tmpl-examples-drawings',
                                drawings: [drawing_1, drawing_2, drawing_4, drawing_5, drawing_6, drawing_7, drawing_8, drawing_9 ]};
    var examples_media      = {header: 'Web', text: '', template: 'tmpl-examples-web', projects: [proj1]};
    
    var VIEW_MODE_INFO      =  { header: 'Info', text: 'About me', subModes: [ info_schedule, info_aboutMe]};
    var VIEW_MODE_CONTACT   =  { header: 'Contact', text: 'Get in touch', template: 'tmpl-contact'};
    var VIEW_MODE_RESUME    =  { header: 'Resume', text: 'My work history', template: 'tmpl-resume'};
    var VIEW_MODE_PERSONAL  =  { header: 'Fun', text: 'Examples of pet projects', subModes: [examples_media, examples_drawings]};
    
    
    
    
    
    
    // ==============================================
    //              Public Variables
    // ==============================================
    
    var self = this;
    
    /**
     * These are the major categories of this application (which will be displayed in the primary navigation.)
     */
    self.modes = [ VIEW_MODE_INFO, VIEW_MODE_CONTACT, VIEW_MODE_RESUME, VIEW_MODE_PERSONAL ];
    
    /**
     * These are the secondary categories for this application that will be displayed in the secondary navigation.
     */
    self.subModes = ko.observable();
    
    /**
     * The currently selected View Mode
     */
    self.chosenMode = ko.observable();
    
    /**
     *  The currently selected Sub View Mode (secondary appliction category, example: "Info"
     *  is a primary category, "About Me" and "Schedule" are secondary).
     */
    self.chosenSubMode = ko.observable();
    
    // ==============================================
    //              Behaviors
    // ==============================================
    
    /**
     * This method will be called when the user clicks on a primary navigation element.
     *
     * @param (Object) The object that we wish to have as our primary data object. 
     */
    self.goToMode = function(mode)
    {
        // set current mode
        self.chosenMode(mode);
        
        // see if the property exists
        if(mode.hasOwnProperty(VIEW_MODE_PROPERTY_SUB_MODE))
        {
            // see if this property is an array
            if(mode[VIEW_MODE_PROPERTY_SUB_MODE] instanceof Array)
            {
                // see if this array has elements in it, and if so, then set the first one as the selected one.
                if(mode[VIEW_MODE_PROPERTY_SUB_MODE].length > 0)
                {
                    // update the array,
                    
                    //  NOTE: that I am calling a method because the Array is now an Observable. 
                     self.subModes(mode[VIEW_MODE_PROPERTY_SUB_MODE]);
                     
                    // delegate to the submode function
                    self.goToSubMode(mode[VIEW_MODE_PROPERTY_SUB_MODE][0]);        
                }
            }
            
        }else{
            // get rid of any existing values in the sub mode array
            
            //  NOTE: that I am calling a method because the Array is now an Observable.
            self.subModes([]);
            
            // send an empty object as the selected SubMode. 
            self.goToSubMode({});
            
        }
        
    };
    
    /**
     * This method will be called with the user clicks on a primary (which defaults to the first
     * sub mode it contains) or secondary navigation element.
     *
     * @param (Object) The data object we wish to have as our secondary mode. 
     */
    self.goToSubMode = function(subMode)
    {
        // set current mode
        self.chosenSubMode(subMode);
    }
    
    self.displayMode = function(mode) {
        //see if there is a template listed for the chosen sub mode, else return the the mode template. 
        // see if the property exists
       if(self.chosenSubMode() !== undefined)
        {
            // see if this property is an array
            if(self.chosenSubMode().hasOwnProperty(VIEW_MODE_PROPERTY_TEMPLATE))
            {
                return self.chosenSubMode()[VIEW_MODE_PROPERTY_TEMPLATE];
            }
            
        }
        
        // assume if the code gets here, that we need to return a default view
           if(self.chosenMode() !== undefined)
        {
            // see if this property is an array
            if(self.chosenMode().hasOwnProperty(VIEW_MODE_PROPERTY_TEMPLATE))
            {
                return self.chosenMode()[VIEW_MODE_PROPERTY_TEMPLATE];
            }
            
        }
        
        // asuume something has gone wrong if it reaches here
        return error_occurred[VIEW_MODE_PROPERTY_TEMPLATE];
        
    }
    
    self.postProcessingLogic = function()
    {
        // now we can do something with template content because it's rendered already
        // $('#content p').fadeIn('slow');
        
        
        switch(self.chosenMode().header)
        {
            case VIEW_MODE_CONTACT.header:
                // init the form to subit in an ajax fashion.
                self.initFormSubmission('#contact_form');
                break;
            case VIEW_MODE_RESUME.header:
                // if there are PDF, then show them. 
                $('a.media').media({width:900, height:1000});
                break;
        }
        
       //$(document).ready( function(){
            
        //});
        
        
       
       
       
    }
    
    
    /**
     *  Used to initialize the form that will submit a POST action to a backend.
     *
     *  @param (Object) aHtmlObject The form that will submit.
     *  @see http://www.devblog.co/easy-jquery-ajax-php-contact-form/
     */
    self.initFormSubmission = function(aHtmlObject)
    {
        $(aHtmlObject).submit(function(e){
            e.preventDefault();
            
            var form = $(this);
            var post_url = form.attr('action');
            var post_data = form.serialize();
            
            
            $('#loader', form).html('<img src="loader.gif" /> Please Wait...');
            
            $.ajax({
                type: 'POST',
                url: post_url,
                data: post_data,
                success: function(msg) {
                    $(form).fadeOut(500, function(){
                    form.html(msg).fadeIn();
                    });
                }
            });
        });
    }
    
    
    // ==============================================
    //              Initialize
    // ==============================================
    
    // initialize the main page we want to display
    self.goToMode(VIEW_MODE_INFO);
}


// Activates knockout.js
ko.applyBindings(new AppViewModel());